package com.example.jpa.crud.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

public class ClassUtils {

    private static final Logger log = LoggerFactory.getLogger(ClassUtils.class);

    private static final String DOT = ".";

    private static final String SLASH = "/";

    private static final String DOT_CLASS = ".class";

    public static String getPackageName(String className) {
        if (className == null) {
            return null;
        }
        int lastDotIndex = className.lastIndexOf(DOT);
        return (lastDotIndex != -1 ? className.substring(0, lastDotIndex) : null);
    }

    @SuppressWarnings("unused")
    public static List<Class<?>> getClassesFromPackage(String packageName) {
        if (packageName == null) {
            return Collections.emptyList();
        }
        final List<Class<?>> classList = new ArrayList<>();
        final List<String> classNames = getClassNamesFromPackage(packageName);
        for (String className : classNames) {
            Class<?> clazz;
            try {
                clazz = Class.forName(className);
            } catch (ClassNotFoundException e) {
                log.error("getClassesFromPackage", e);
                clazz = null;
            }
            if (clazz != null) {
                classList.add(clazz);
            }
        }
        return classList;
    }

    public static List<String> getClassNamesFromPackage(String packageName) {
        if (packageName == null) {
            return Collections.emptyList();
        }
        final List<String> classNameList = new ArrayList<>();
        final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        try {
            final Enumeration<URL> resources = contextClassLoader.getResources(packageName.replace(DOT, SLASH));
            while (resources.hasMoreElements()) {
                final URL url = resources.nextElement();
                final File file = new File(url.getFile());
                classNameList.addAll(getClassNames(file, packageName));
            }
        } catch (Exception e) {
            log.error("getClassNamesFromPackage", e);
            return Collections.emptyList();
        }
        return classNameList;
    }

    private static List<String> getClassNames(File file, String classNameBuilder) {
        final List<String> classNameList = new ArrayList<>();
        if (file.isDirectory()) {
            final File[] files = file.listFiles();
            if (files != null) {
                for (File f : files) {
                    classNameList.addAll(getClassNames(f, classNameBuilder + DOT + f.getName()));
                }
            }
        } else {
            final String name = file.getName();
            if (name.endsWith(DOT_CLASS)) {
                final String className = classNameBuilder.substring(0, classNameBuilder.lastIndexOf(DOT));
                classNameList.add(className);
            }
        }
        return classNameList;
    }

}
